package net.lab1024.sa.gateway.processor;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import net.lab1024.sa.gateway.dto.ApiProcessDTO;
import net.lab1024.sa.gateway.util.TrafficUtils;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.codec.multipart.Part;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import reactor.core.publisher.Mono;

/**
 * 参数校验处理器
 */
@Component
public class ParamProcessor extends AbstractApiProcessor {
    private static final long MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
    private static final String[] ALLOWED_FILE_TYPES = {".jpg", ".png", ".pdf"};

    @Override
    protected Mono<Void> doProcess(ApiProcessDTO dto) {

        // 根据Content-Type判断请求类型并处理
        String contentType = dto.getExchange().getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);

        if (TrafficUtils.isMultipartRequest(dto.getExchange())) {
            // 文件上传请求处理
            return validateFile(dto);
        } else if (contentType != null && contentType.startsWith(MediaType.APPLICATION_JSON_VALUE)) {
            // JSON请求处理
            return validateJsonParams(dto);
        } else if (contentType != null && contentType.startsWith(MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {
            // 表单请求处理
            return validateFormParams(dto);
        } else {
            // 无法识别的Content-Type，返回错误
            return Mono.error(new RuntimeException("UNSUPPORTED_CONTENT_TYPE: " + contentType));
        }
    }

    // 文件验证：大小+类型
    private Mono<Void> validateFile(ApiProcessDTO dto) {
        MultiValueMap<String, Part> multipartData = (MultiValueMap<String, Part>) dto.getData();
        if (multipartData == null) {
            return Mono.error(new RuntimeException("MULTIPART_DATA_MISSING"));
        }

        Part filePart = multipartData.getFirst("file");
        if (filePart == null) {
            return Mono.error(new RuntimeException("FILE_PARAM_MISSING"));
        }

        // 验证文件大小
        return DataBufferUtils.join(filePart.content())
                .flatMap(dataBuffer -> {
                    long fileSize = dataBuffer.readableByteCount();
                    DataBufferUtils.release(dataBuffer); // 释放缓冲区，避免内存泄漏
                    if (fileSize > MAX_FILE_SIZE) {
                        return Mono.error(new RuntimeException("FILE_TOO_LARGE"));
                    }
                    // 验证文件类型
                    String filename = filePart.name();
                    if (!isAllowedFileType(filename)) {
                        return Mono.error(new RuntimeException("FILE_TYPE_NOT_ALLOWED"));
                    }
                    return Mono.empty();
                });
    }

    // JSON参数验证
    private Mono<Void> validateJsonParams(ApiProcessDTO dto) {
        Object data = dto.getData();

        // 如果数据为null，尝试从请求体中读取
        if (data == null) {
            return readJsonBody(dto.getExchange())
                    .doOnNext(dto::setData)
                    .flatMap(this::validateJsonData);
        } else {
            return validateJsonData(data);
        }
    }

    // 验证JSON数据
    private Mono<Void> validateJsonData(Object data) {
        if (data instanceof JSONObject) {
            // JSON数据处理
            // JSONObject已经验证过了，直接通过
            return Mono.empty();
        } else if (data instanceof String) {
            // 字符串数据处理（可能是JSON字符串）
            String jsonData = (String) data;
            // 检查是否为空或空白
            if (jsonData.trim().isEmpty()) {
                return Mono.error(new RuntimeException("EMPTY_JSON_DATA"));
            }

            try {
                JSON.parseObject(jsonData);
                // 如果能成功解析为JSON对象，则认为是有效的
                return Mono.empty();
            } catch (Exception e) {
                // 记录原始错误信息，但返回更友好的错误信息
                return Mono.error(new RuntimeException("INVALID_JSON_FORMAT: " + e.getMessage() + ", data: " + jsonData));
            }
        } else {
            return Mono.error(new RuntimeException("UNSUPPORTED_JSON_DATA_FORMAT"));
        }
    }

    // 表单参数验证
    private Mono<Void> validateFormParams(ApiProcessDTO dto) {
        Object data = dto.getData();

        if (data instanceof MultiValueMap) {
            // 表单数据处理
            // MultiValueMap已经验证过了，直接通过
            return Mono.empty();
        } else {
            return Mono.error(new RuntimeException("INVALID_FORM_DATA_FORMAT"));
        }
    }

    // 从请求体中读取JSON数据
    private Mono<Object> readJsonBody(org.springframework.web.server.ServerWebExchange exchange) {
        return exchange.getRequest().getBody()
                .collectList()
                .map(dataBuffers -> {
                    StringBuilder bodyBuilder = new StringBuilder();
                    dataBuffers.forEach(dataBuffer -> {
                        byte[] bytes = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(bytes);
                        DataBufferUtils.release(dataBuffer);
                        bodyBuilder.append(new String(bytes));
                    });

                    String body = bodyBuilder.toString().trim();
                    // 检查是否为空
                    if (body.isEmpty()) {
                        return "{}"; // 返回空的JSON对象而不是空字符串
                    }

                    // 尝试解析为JSON对象
                    try {
                        return (Object) JSON.parseObject(body);
                    } catch (Exception e) {
                        // 如果解析失败，返回原始字符串，让validateJsonData处理错误
                        return body;
                    }
                });
    }

    // 检查文件类型是否允许
    private boolean isAllowedFileType(String filename) {
        for (String type : ALLOWED_FILE_TYPES) {
            if (filename.toLowerCase().endsWith(type)) {
                return true;
            }
        }
        return false;
    }

}